
#include "circle_api.h"
#include "WavFile.h"

uint8_t HeaderTabIndex = 0;
WAVE_FormatTypeDef  WAVE_Format;
uint32_t DataStartAddr = 0x0;
uint8_t AudioFileHeader[HEADER_SIZE];

/*******************************************************************************
* Function Name  : WaveParsing
* Description    : Taken from the STM examples (i2s_codec.c, UM0549.zip, firmware
*                  of the ST-Eval board for the STM32F103E).
*                  Checks the format of the .WAV file and gets information about
*                  the audio format. This is done by reading the value of a
*                  number of parameters stored in the file header and comparing
*                  these to the values expected authenticates the format of a
*                  standard .WAV  file (44 bytes will be read). If  it is a valid
*                  .WAV file format, it continues reading the header to determine
*                  the  audio format such as the sample rate and the sampled data
*                  size. If the audio format is supported by this application,
*                  it retrieves the audio format in WAVE_Format structure and
*                  returns a zero value. Otherwise the function fails and the
*                  return value is nonzero.In this case, the return value specifies
*                  the cause of  the function fails. The error codes that can be
*                  returned by this function are declared in the header file.
* Input          : None
* Output         : None
* Return         : Zero value if the function succeed, otherwise it return
*                  a nonzero value which specifies the error code.
*******************************************************************************/
ErrorCode WavFile_CODEC_Parsing(uint8_t * HeaderTab)
    {
    uint32_t Temp = 0x00;
    uint32_t ExtraFormatBytes = 0; 
    AUDIO_Frequency_enum i2saudiofreq;

    /* Initialize the HeaderTabIndex variable */
    HeaderTabIndex = 0;

    /* Read chunkID, must be 'RIFF'	----------------------------------------------*/
    Temp = ReadUnit(4, BigEndian);
    if(Temp != ChunkID)
        {
        DRAW_Puts("\nError: Invalid RIFF Id");
        return(Invalid_RIFF_ID);
        }
    /* Read the file length ----------------------------------------------------*/
    WAVE_Format.RIFFchunksize = ReadUnit(4, LittleEndian);

    /* Read the file format, must be 'WAVE' ------------------------------------*/
    Temp = ReadUnit(4, BigEndian);
    if(Temp != FileFormat)
        {
        DRAW_Puts("\nError: Invalid WAVE Format");
        return(Invalid_WAVE_Format);
        }
    /* Read the format chunk, must be 'fmt ' -----------------------------------*/
    Temp = ReadUnit(4, BigEndian);
    if(Temp != FormatID)
        {
        DRAW_Puts("\nError: Invalid Format chunk");
        return(Invalid_FormatChunk_ID);
        }
    /* Read the length of the 'fmt' data, must be 0x10 -------------------------*/
    Temp = ReadUnit(4, LittleEndian);
    if(Temp != 0x10)
        {
        ExtraFormatBytes = 1;
        }
    /* Read the audio format, must be 0x01 (PCM) -------------------------------*/
    WAVE_Format.FormatTag = ReadUnit(2, LittleEndian);
    if(WAVE_Format.FormatTag != WAVE_FORMAT_PCM)
        {
        DRAW_Puts("\nError: Unsupported Format tag");
        return(Unsupporetd_FormatTag);	
        }
    /* Read the number of channels: 0x02->Stereo 0x01->Mono --------------------*/
    WAVE_Format.NumChannels = ReadUnit(2, LittleEndian);

    /* Read the Sample Rate ----------------------------------------------------*/
    WAVE_Format.SampleRate = ReadUnit(4, LittleEndian);

    /* Update the I2S_AudioFreq value according to the .WAV file Sample Rate */
    switch(WAVE_Format.SampleRate)
        {
        case SampleRate_8000 : i2saudiofreq = FRQ_8KHZ;  break; 
        case SampleRate_16000: i2saudiofreq = FRQ_16KHZ; break; 
        case SampleRate_22050: i2saudiofreq = FRQ_22KHZ; break; 	
        case SampleRate_44100: i2saudiofreq = FRQ_44KHZ; break;  		
        case SampleRate_48000: i2saudiofreq = FRQ_48KHZ; break;  		
        default: 
            DRAW_Puts("\nError: Unsupported sample rate");
            return(Unsupporetd_Sample_Rate);
        }	
    WAVE_Format.SampleRate = i2saudiofreq;
    
    /* Read the Byte Rate ------------------------------------------------------*/
    WAVE_Format.ByteRate = ReadUnit(4, LittleEndian);

    /* Read the block alignment ------------------------------------------------*/
    WAVE_Format.BlockAlign = ReadUnit(2, LittleEndian);

    /* Read the number of bits per sample --------------------------------------*/
    WAVE_Format.BitsPerSample = ReadUnit(2, LittleEndian);
    if ( ( WAVE_Format.BitsPerSample != Bits_Per_Sample_16 ) && ( WAVE_Format.BitsPerSample != Bits_Per_Sample_8 ) )
        {
        return(Unsupporetd_Bits_Per_Sample);
        }

    /* If there are Extra format bytes, these bytes will be defined in "Fact Chunk" */
    if(ExtraFormatBytes == 1)
        {
        /* Read th Extra format bytes, must be 0x00 ------------------------------*/
        Temp = ReadUnit(2, LittleEndian);
        if(Temp != 0x00)
            {
            return(Unsupporetd_ExtraFormatBytes);
            }
        /* Read the Fact chunk, must be 'fact' -----------------------------------*/
        Temp = ReadUnit(4, BigEndian);
        if(Temp != FactID)
            {
            return(Invalid_FactChunk_ID);
            }
        /* Read Fact chunk data Size ---------------------------------------------*/
        Temp = ReadUnit(4, LittleEndian);

        /* Set the index to start reading just after the header end */
        HeaderTabIndex += Temp;
        }
    /* Read the Data chunk, must be 'data' -------------------------------------*/
    Temp = ReadUnit(4, BigEndian);
    if(Temp != DataID)
        {
        return(Invalid_DataChunk_ID);
        }
    /* Read the number of sample data ------------------------------------------*/
    WAVE_Format.DataSize = ReadUnit(4, LittleEndian);

    /* Set the data pointer at the beginning of the effective audio data */
    DataStartAddr += HeaderTabIndex;

    return(Valid_WAVE_File);	
    }

/*******************************************************************************
* Function Name  : ReadUnit
* Description    : Reads a number of bytes from the SD card and reorder them
*                  in Big or little endian.
* Input          : - NbrOfBytes : number of bytes to read.
*                    This parameter must be a number between 1 and 4.
*                  - ReadAddr : external memory address to read from.
*                  - Endians : specifies the bytes endianness.
*                    This parameter can be one of the following values:
*                          - LittleEndian
*                          - BigEndian
* Output         : None
* Return         : Bytes read from the SD-Card.
*******************************************************************************/
static uint32_t ReadUnit(u8 NbrOfBytes, Endianness BytesFormat)
    {
    u32 index = 0;
    u32 Temp = 0;

    if(BytesFormat == LittleEndian)
        {
        for(index = 0; index < NbrOfBytes; index++)
            {
            Temp |= AudioFileHeader[HeaderTabIndex++] << (index * 8);
            }
        }
    else
        {
        for(index = NbrOfBytes; index != 0; index--)
            {
            Temp |= AudioFileHeader[HeaderTabIndex++] << ((index-1) * 8);
            }
        }
    return Temp;
    }
